﻿using System;
using Microsoft.Win32;

namespace Useful.Sys
{
    public class RegistryException : Exception
    {
        public RegistryException(string msg, Exception ex)
            : base(msg, ex)
        {
        }
    }


    public class RegHelper
    {
        private string _RegPath;
        private RegistryKey rootKey;

        public RegHelper(string RegPath)
        {
            _RegPath = RegPath;

            rootKey = Registry.CurrentUser.OpenSubKey(_RegPath);

            if (rootKey == null)
                Registry.CurrentUser.CreateSubKey(_RegPath);

            rootKey = Registry.CurrentUser.OpenSubKey(_RegPath, true);

            if (rootKey == null)
                throw new RegistryException(String.Format("Не удалось получить/создать ветку реестра '{0}'", RegPath), null);
        }

        /// <summary>
        /// Получение значения из реестра
        /// </summary>
        /// <param name="valueName">Параметр</param>
        /// <param name="defaultValue">Значение по умолчанию</param>
        /// <returns>Значение параметра</returns>
        public object GetObjectCore(string valueName, object defaultValue)
        {
            object res = rootKey.GetValue(valueName, defaultValue);

            if (res == null)
                res = defaultValue;

            return res;
        }

        public object GetObjectCore(string valueName, string subkey, object defaultValue)
        {
            object res = null;
            RegistryKey rk = rootKey.OpenSubKey(subkey, true);

            if (rk != null)
                res = rk.GetValue(valueName, defaultValue);

            if (res == null)
                res = defaultValue;

            return res;
        }

        /// <summary>
        /// Получить строку (или Empty) из реестра
        /// </summary>
        /// <param name="valueName">Параметр</param>
        /// <returns>Значение</returns>
        public string GetStringCore(string valueName)
        {
            object obj = rootKey.GetValue(valueName, null);

            if (obj != null)
                return obj.ToString();
            else
                return String.Empty;
        }

        /// <summary>
        /// Получить строку (или null) из реестра
        /// </summary>
        /// <param name="valueName">Параметр</param>
        /// <returns>Значение</returns>
        public string GetStringOrNull(string valueName)
        {
            object obj = GetObjectCore(valueName, null);

            return obj != null ? obj.ToString() : null;
        }

        /// <summary>
        /// Установить значение параметра
        /// </summary>
        /// <param name="valueName">Параметр</param>
        /// <param name="val">Значение</param>
        public void SetValue(string valueName, object val)
        {
            rootKey.SetValue(valueName, val);
        }

        /// <summary>
        /// Установить значение параметра с заданием его типа String
        /// </summary>
        /// <param name="valueName">Параметр</param>
        /// <param name="val">Значение</param>
        public void SetValueString(string valueName, string val)
        {
            if (val != null)
                rootKey.SetValue(valueName, val, RegistryValueKind.String);
        }

        public void SetValueString(string valueName, string subkey, string val)
        {
            RegistryKey rk = rootKey.OpenSubKey(subkey, true);

            if (rk == null)
            {
                rootKey.CreateSubKey(subkey);
                rk = rootKey.OpenSubKey(subkey, true);
            }

            rk.SetValue(valueName, val, RegistryValueKind.String);
        }

        /// <summary>
        /// Получить параметр реестра типа int
        /// </summary>
        /// <param name="propName">Параметр</param>
        /// <param name="defaullValue">Значение по умолчанию</param>
        /// <returns>Значение</returns>
        public int GetPropertyInt(string propName, int defaullValue)
        {
            return Convert.ToInt32(GetObjectCore(propName, defaullValue));
        }

        public int GetPropertyInt(string propName, string subkey, int defaullValue)
        {
            return Convert.ToInt32(GetObjectCore(propName, subkey, defaullValue));
        }

        public string GetPropertyString(string propName, string subkey, string defaullValue)
        {
            return GetObjectCore(propName, subkey, defaullValue).ToString();
        }

        /// <summary>
        /// Установить значение параметра реестра
        /// </summary>
        /// <param name="propName">Параметр</param>
        /// <param name="value">Значение</param>
        public void SetProperty(string propName, int value)
        {
            SetValueString(propName, value.ToString());
        }

        public void SetProperty(string propName, string subkey, int value)
        {
            SetValueString(propName, subkey, value.ToString());
        }

        public void SetProperty(string propName, string subkey, string value)
        {
            SetValueString(propName, subkey, value);
        }

        public bool GetPropertyBool(string propName, bool defaullValue)
        {
            return Convert.ToBoolean(GetObjectCore(propName, defaullValue));
        }

        public byte[] GetPropertyBytes(string propName, byte[] defaullValue)
        {
            object data = GetObjectCore(propName, defaullValue);

            return data != null ? (byte[])data : null;
        }

        public void SetProperty(string propName, bool value)
        {
            SetValue(propName, value ? 1 : 0);
        }

        public void SetProperty(string propName, byte[] value)
        {
            if (value != null)
                SetValue(propName, value);
        }

        public void SetProperty(string propName, string value)
        {
            SetValueString(propName, value);
        }

        public string GetPropertyString(string propName, string defaullValue)
        {
            return Convert.ToString(GetObjectCore(propName, defaullValue));
        }

        public string GetPropertyString(string propName)
        {
            return Convert.ToString(GetObjectCore(propName, String.Empty));
        }

        public string[] GetSubKeyNames(string keyName)
        {
            try
            {
                return rootKey.OpenSubKey(keyName).GetValueNames();
            }
            catch (NullReferenceException ex)
            {
                throw new RegistryException("Не найдена ветка реестра.", ex);
            }
        }

        public void ClearSubKeyNames(string keyName)
        {
            try
            {
                rootKey.DeleteSubKeyTree(keyName);
            }
            catch (NullReferenceException ex)
            {
                throw new RegistryException("Не найдена ветка реестра.", ex);
            }
        }

        public void SetSubKeyName(string keyName, string name)
        {
            try
            {
                RegistryKey rk = rootKey.OpenSubKey(keyName, true);

                if (rk == null)
                    rootKey.CreateSubKey(keyName);

                rk = rootKey.OpenSubKey(keyName, true);

                if (rk.GetValue(name, null) == null)
                    rk.SetValue(name, String.Empty, RegistryValueKind.String);
            }
            catch (NullReferenceException ex)
            {
                throw new RegistryException("Не найдена ветка реестра.", ex);
            }
        }

        public void DeleteValue(string name)
        {
            rootKey.DeleteValue(name, false);
        }
    }
}
